package com.ashlikun.glideutils

import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.widget.ImageView
import android.widget.ImageView.ScaleType
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory.CacheDirectoryGetter
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.CustomViewTarget
import com.bumptech.glide.request.target.ImageViewTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.target.ViewTarget
import com.bumptech.glide.request.transition.Transition
import jp.wasabeef.glide.transformations.RoundedCornersTransformation
import okhttp3.Call
import okhttp3.OkHttpClient
import java.io.File

/**
 * 作者　　: 李坤
 * 创建时间: 2017/12/29 16:59
 * 邮箱　　：496546144@qq.com
 *
 *
 * 功能介绍：Glide的封装
 * Object的参数可以是资源id，网络文件，本地文件，url
 */
object GlideUtils {
    //是否调试
    var isDebug = false
    private var context: Context? = null

    //设置默认的错误图片
    var errorRes = R.drawable.material_default_image_1_1

    //设置默认的占位图
    var placeholderRes = R.color.glide_placeholder_color

    //错误图的缩放类型
    var errorScaleType: ScaleType? = ScaleType.CENTER_INSIDE

    //展位图的缩放类型
    var placeholderScaleType: ScaleType? = ScaleType.CENTER_INSIDE

    //设置缓存,在application设置
    var diskLruCacheFactory: DiskLruCacheFactory? = null

    //Glide 初始化的时候设置GlideBuilder
    var initApplyOptions: ((builder: GlideBuilder, option: RequestOptions) -> Unit)? = null

    @Volatile
    var internalClient: Call.Factory? = null
    fun init(context: Context?, okHttpClient: OkHttpClient?) {
        GlideUtils.context = context
        internalClient = okHttpClient
    }

    /**
     * 下载
     */
    fun downloadBitmap(context: Any?, url: String?, downloadCallbacl: OnDownloadCallback?) {
        downloadFile(context, url, downloadCallbacl)
    }

    /**
     * 加载缓存
     */
    fun downloadCache(context: Any?, url: String?, downloadCallbacl: OnDownloadCallback?) {
        val file = getCache(url)
        if (file == null || !file.exists()) {
            //没有缓存，加载缓存
            downloadFile(context, url, downloadCallbacl)
        } else {
            //已经有缓存就使用缓存回调
            downloadCallbacl?.invoke(file)
        }
    }

    /**
     * 下载文件
     */
    fun downloadFile(context: Any?, url: String?, downloadCallbacl: OnDownloadCallback?) {
        load(context).download(url ?: "").into(object : CustomTarget<File?>() {
            override fun onLoadFailed(errorDrawable: Drawable?) {
                super.onLoadFailed(errorDrawable)
                downloadCallbacl?.invoke(null)
            }

            override fun onResourceReady(resource: File, transition: Transition<in File?>?) {
                downloadCallbacl?.invoke(resource)
            }

            override fun onLoadCleared(placeholder: Drawable?) {}
        })
    }

    /**
     * 下载文件
     */
    fun getFile(context: Any?, url: String?, target: Target<File>?) {
        var target = target
        if (target == null) {
            target = object : OnCustomTarget<File>() {
                override fun onResourceReady(resource: File, transition: Transition<in File?>?) {}
            }
        }
        load(context).asFile().load(url ?: "").into<Target<File>>(target)
    }

    /**
     * 下载Bitmap
     */
    fun getBitmap(context: Any?, url: String?, target: Target<Bitmap>?) {
        var target = target
        if (target == null) {
            target = object : OnCustomTarget<Bitmap>() {
                override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {}
            }
        }
        load(context).asBitmap().load(url ?: "").into<Target<Bitmap>>(target)
    }

    /**
     * 下载Draweable  一般如果不知道是Bitmap还是Drawable就用这个
     */
    fun getDrawable(context: Any?, url: String?, target: Target<Drawable>?) {
        var target = target
        if (target == null) {
            target = object : OnCustomTarget<Drawable>() {
                override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {}
            }
        }
        load(context).asDrawable().load(url ?: "").into<Target<Drawable>>(target)
    }

    /**
     * 是否是网络url或者文件
     */
    fun isHttpOrFileUrl(url: String?): Boolean {
        if (url != null) {
            if (url.startsWith("http://") || url.startsWith("https://")) {
                return true
            } else if (url.startsWith("/storage") || url.startsWith("storage") || url.startsWith("/data") || url.startsWith("data")) {
                return true
            }
        }
        return false
    }

    /**
     * 获取中间裁剪的圆角图
     */
    fun getRoundedOptions(radius: Int): RequestOptions {
        return RequestOptions().transform(
            CenterCrop(),
            RoundedCornersTransformation(radius, 0)
        )
    }

    //获取中间裁剪的圆形
    val circleOptions: RequestOptions
        get() = RequestOptions().transform(
            CenterCrop(),
            CircleCrop()
        )

    /**
     * 获取Glide造成的缓存大小
     */
    fun getCacheSize(context: Context?): Double {
        try {
            return getFolderSize(getCacheDir(context)).toDouble()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return (-1).toDouble()
    }

    /**
     * 获取缓存目录
     */
    fun getCacheDir(context: Context?): File? {
        if (diskLruCacheFactory == null) {
            diskLruCacheFactory = InternalCacheDiskCacheFactory(context)
        }
        //反射获取私有属性
        try {
            val field = DiskLruCacheFactory::class.java.getDeclaredField("cacheDirectoryGetter")
            field.isAccessible = true
            val cacheDirectoryGetter = field[diskLruCacheFactory] as CacheDirectoryGetter
            return cacheDirectoryGetter.cacheDirectory
        } catch (e: NoSuchFieldException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 这个图片是否有缓存
     * 只能在子线程
     */
    fun isCache(url: String?): Boolean {
        return getCache(url) != null
    }

    /**
     * 获取缓存文件
     * 只能在子线程
     * onlyRetrieveFromCache 是否只是从缓存中获取
     */
    fun getCache(url: String?): File? {
        return try {
            if (diskLruCacheFactory == null) {
                diskLruCacheFactory = InternalCacheDiskCacheFactory(context)
            }
            val wrapper = diskLruCacheFactory!!.build()
            wrapper!![GlideUrl(url)]
        } catch (e: Exception) {
            null
        }
    }

    /**
     * 获取指定文件夹内所有文件大小的和
     *
     * @param file file
     * @return size
     * @throws Exception
     */
    @Throws(Exception::class)
    private fun getFolderSize(file: File?): Long {
        var size: Long = 0
        try {
            val fileList = file!!.listFiles()
            for (aFileList in fileList) {
                size = if (aFileList.isDirectory) {
                    size + getFolderSize(aFileList)
                } else {
                    size + aFileList.length()
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return size
    }

    fun getImageView(target: Target<Drawable>?): ImageView? {
        if (target is ImageViewTarget<*>) {
            return (target as ImageViewTarget<*>).view
        } else if (target is CustomViewTarget<*, *>) {
            val view = (target as CustomViewTarget<*, *>).view
            if (view is ImageView) {
                return view
            }
        } else if (target is ViewTarget<*, *>) {
            val view = (target as ViewTarget<*, *>).view
            if (view is ImageView) {
                return view
            }
        }
        return null
    }

    fun load(context: Any?): GlideRequests {
        if (context is FragmentActivity) {
            return GlideApp.with((context as FragmentActivity?)!!)
        } else if (context is Activity) {
            return GlideApp.with((context as Activity?)!!)
        } else if (context is Fragment) {
            return GlideApp.with((context as Fragment?)!!)
        } else if (context is ImageView) {
            return GlideApp.with((context as ImageView?)!!)
        } else if (context is Context) {
            return GlideApp.with((context as Context?)!!)
        }
        throw NullPointerException("context error")
    }

    fun setScaleType(imageView: ImageView?, isSetScaleType: Boolean) {
        if (imageView != null && isSetScaleType) {
            val old = imageView.scaleType
            if (placeholderScaleType != null && old != placeholderScaleType) {
                imageView.scaleType = placeholderScaleType
                imageView.setTag(R.id.glide_utils_placeholderScaleType, true)
                imageView.setTag(R.id.glide_utils_placeholderScaleType_original, old)
            }
        }
    }

    fun setErrorScaleType(imageView: ImageView?, isSetScaleType: Boolean) {
        if (imageView != null && isSetScaleType) {
            val old = imageView.scaleType
            if (errorScaleType != null && old != errorScaleType) {
                imageView.scaleType = errorScaleType
                imageView.setTag(R.id.glide_utils_placeholderScaleType, true)
                imageView.setTag(R.id.glide_utils_placeholderScaleType_original, old)
            }
        }
    }

    fun resetScaleType(imageView: ImageView?, isSetScaleType: Boolean) {
        if (imageView != null && isSetScaleType) {
            var isFailedSetScale = false
            if (imageView.getTag(R.id.glide_utils_placeholderScaleType) != null) {
                isFailedSetScale = imageView.getTag(R.id.glide_utils_placeholderScaleType) as Boolean
            }
            var oldScaleType: ScaleType? = null
            if (imageView.getTag(R.id.glide_utils_placeholderScaleType_original) != null) {
                oldScaleType = imageView.getTag(R.id.glide_utils_placeholderScaleType_original) as ScaleType
            }
            if (isFailedSetScale && oldScaleType != null) {
                //还原
                imageView.scaleType = oldScaleType
                imageView.setTag(R.id.glide_utils_placeholderScaleType, null)
                imageView.setTag(R.id.glide_utils_placeholderScaleType_original, null)
            }
        }
    }
}
